moddbfandomcom-20200213-history
SDL ttf:Tutorials:Fonts in OpenGL
Introduction Since SDL_ttf is a great library for SDL, I figured that it would be damned handy if we could use SDL_ttf in OpenGL, after experimenting a bit with the code, I succeeded in doing this. And it's really easy, it works in the same way as using an SDL_Surface * as an OpenGL texture. "Why do this?" you might ask. One thing is you do not need any other library than SDL ( and its additional ones, like SDL_ttf ) to get fonts, and we do not need to use plain old and sometimes annoying bitmap fonts, the text made here is also rotatable, scalable, ... since it's made out of a texture. If you're interested, then by all means, read on! Code By reading and working with this tutorial, I assume you know how SDL_ttf works and how OpenGL textures work. I also assume you have the correct libraries, DLL's, etc.. to be able to write code for these libraries. Mandatory Setup First we need to make sure blending and textures are enabled, and set up a correct blending method: ... glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ... Prototype This is the prototype ( or declaration ) of the function. This isn't necessary in some cases, but I'm going to use it to explain what every argument will be used for. Font: This object will contain the font used by the text. R: Represents the amount of red the user wants in his text. G: Represents the amount of green the user wants in his text. B: Represents the amount of blue the user wants in his text. X: The position on the x-axis of the text on the screen. Y: The position on the y-axis of the text on the screen. Z: The position on the z-axis of the text on the screen. Text: The text that needs to be displayed. void RenderText(const TTF_Font *Font, const GLubyte& R, const GLubyte& G, const GLubyte& B, const double& X, const double& Y, const double& Z, const std::string& Text); Variables The SDL_Color simply stores the given R, G and B values for the font. Then we create an SDL_Surface* that will represent the asked font. Note that Text is an std::string so we have to convert it to a C-string ( since SDL is coded in C ). the Texture will contain the data for the font. SDL_Color Color = {R, G, B}; SDL_Surface *Message = TTF_RenderText_Blended(const_cast(Font), Text.c_str(), Color); unsigned Texture = 0; Texture Generation I'm not really going to explain this, since you should know what it all does if you've learned OpenGL. Perhaps the last function call needs a bit of explanation; the first parameters are obvious I think; we want to generate a 2D texture, with 0 level of detail, the internal format is RGBA, then we specify the width and height of the texture ( using the SDL_Surface* ), and we want no border for our texture. Then we use GL_BGRA, this might seem a bit odd, but this can depend on what you've specified for glBlendFunc, in my case, SDL and OpenGL use different types of color values, so I'll have to use GL_BGRA, it's possible that you need to use another value, like GL_RGBA, to get the desired effect. And finally, we need to specify an array of unsigned bytes that contains the pixels of the texture, luckily SDL also uses a void pointer for it's pixels, so we can simply use them in the OpenGL texture. glGenTextures(1, &Texture); glBindTexture(GL_TEXTURE_2D, Texture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Message->w, Message->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, Message->pixels); Actual Drawing I think this is self-explanatory. We simply draw a rectangle with the width and height of the texture and on the given coordinates, using the texture we generated from the SDL_Surface*. Note that the texture was already bound while generating is and there is no need to bind it again. glBegin(GL_QUADS); glTexCoord2d(0, 0); glVertex3d(X, Y, Z); glTexCoord2d(1, 0); glVertex3d(X+Message->w, Y, Z); glTexCoord2d(1, 1); glVertex3d(X+Message->w, Y+Message->h, Z); glTexCoord2d(0, 1); glVertex3d(X, Y+Message->h, Z); glEnd(); Cleanup We no longer need the texture, so we'll delete it and the SDL_Surface* is no longer required either. glDeleteTextures(1, &Texture); SDL_FreeSurface(Message); Function And finally, the entire function: void RenderText(const TTF_Font *Font, const GLubyte& R, const GLubyte& G, const GLubyte& B, const double& X, const double& Y, const double& Z, const std::string& Text) { /*Create some variables.*/ SDL_Color Color = {R, G, B}; SDL_Surface *Message = TTF_RenderText_Blended(const_cast(Font), Text.c_str(), Color); unsigned Texture = 0; /*Generate an OpenGL 2D texture from the SDL_Surface*.*/ glGenTextures(1, &Texture); glBindTexture(GL_TEXTURE_2D, Texture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Message->w, Message->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, Message->pixels); /*Draw this texture on a quad with the given xyz coordinates.*/ glBegin(GL_QUADS); glTexCoord2d(0, 0); glVertex3d(X, Y, Z); glTexCoord2d(1, 0); glVertex3d(X+Message->w, Y, Z); glTexCoord2d(1, 1); glVertex3d(X+Message->w, Y+Message->h, Z); glTexCoord2d(0, 1); glVertex3d(X, Y+Message->h, Z); glEnd(); /*Clean up.*/ glDeleteTextures(1, &Texture); SDL_FreeSurface(Message); } That's it! You're now able to draw True Type Fonts ( TTF ) in OpenGL using 2D textures! Author: Creature